package com.tanhua.dubbo.server.api;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.alibaba.dubbo.config.annotation.Service;
import com.mongodb.client.result.DeleteResult;
import com.tanhua.dubbo.server.pojo.*;
import com.tanhua.dubbo.server.service.IdService;
import com.tanhua.dubbo.server.vo.PageInfo;
import com.tanhua.dubbo.server.pojo.Log;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Author: JinboYang
 * @Description:
 * @Date: Created in 下午 20:23 2021/1/5
 * @ModifiedBy:
 */
@Service(version = "1.0.0", interfaceClass = QuanZiApi.class)
@Slf4j
public class QuanZiApiImpl implements QuanZiApi {
    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private IdService idService;

    @Override
    public String savePublish(Publish publish) {
        //校验
        if (publish == null) {
            return null;
        }
        if (publish.getUserId() == null) {
            return null;
        }
        try {
            //设置创建时间
            publish.setCreated(System.currentTimeMillis());
            publish.setSeeType(1);
            //设置id
            publish.setId(ObjectId.get());

            //增加自增长id
            publish.setPid(this.idService.createdId("publish",publish.getId().toHexString()));


            //保存发布
            this.mongoTemplate.save(publish);

            //构建相册对象
            Album album = new Album();
            album.setId(ObjectId.get());
            album.setCreated(System.currentTimeMillis());
            album.setPublishId(publish.getId());
            this.mongoTemplate.save(album, "quanzi_album_" + publish.getUserId());

            //写入好友的时间线中
            Criteria criteria = Criteria.where("userId").is(publish.getUserId());
            List<Users> users = this.mongoTemplate.find(Query.query(criteria), Users.class);
            for (Users user : users) {
                //构建时间线对象
                TimeLine timeLine = new TimeLine();
                timeLine.setPublishId(publish.getId());
                timeLine.setDate(System.currentTimeMillis());
                timeLine.setUserId(user.getUserId());
                timeLine.setId(ObjectId.get());
                //保存
                this.mongoTemplate.save(timeLine, "quanzi_time_line_" + user.getFriendId());
            }
        } catch (Exception e) {
            log.error("发布圈子出错", e);
            return publish.getId().toHexString();
        }
        return null;
    }

    @Override
    public PageInfo<Publish> queryPublishList(Long userId, Integer page, Integer pageSize) {

        //我们先查询自己的时间线表
        PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.desc("date")));

        Query query = new Query().with(pageRequest);
        String tableName = null;

        if (userId == null) {
            //推荐表
            tableName = "quanzi_time_line_recommend";
        } else {
            tableName = "quanzi_time_line_" + userId;
        }

        List<TimeLine> timeLines = this.mongoTemplate.find(query, TimeLine.class, tableName);
        List<ObjectId> publishIds = timeLines.stream().map(TimeLine::getPublishId).collect(Collectors.toList());

        Query queryPublish = Query.query(Criteria.where("id").in(publishIds)).with(Sort.by(Sort.Order.desc("created")));
        List<Publish> publishList = this.mongoTemplate.find(queryPublish, Publish.class);

        PageInfo<Publish> pageInfo = new PageInfo<>();
        pageInfo.setPageSize(pageSize);
        pageInfo.setPageNum(page);
        pageInfo.setRecords(publishList);
        return pageInfo;
    }

    /**
     * @Description: 点赞
     * @Param:[userId, publishId]
     * @return:boolean
     * @Author:JinboYang
     * @Date:2021/1/7
     */
    @Override
    public boolean saveLikeComment(Long userId, String publishId) {
        Query query = Query.query(Criteria.where("userId").is(userId)
                .and("publishId").is(new ObjectId(publishId))
                .and("commentType").is(1));
        long count = this.mongoTemplate.count(query, Comment.class);
        if (count > 0) {
            return false;
        }
        return this.saveComment(userId, publishId, 1, null);
    }

    /**
     * @Description: 取消点赞喜欢
     * @Param:[userId, publishId, commentType]
     * @return:boolean
     * @Author:JinboYang
     * @Date:2021/1/7
     */
    @Override
    public boolean removeComment(Long userId, String publishId, Integer commentType) {
        Query query = Query.query(Criteria.where("userId").is(userId)
                .and("publishId").is(new ObjectId(publishId))
                .and("commentType").is(commentType));
        DeleteResult remove = this.mongoTemplate.remove(query, Comment.class);
        return remove.getDeletedCount() > 0;
    }

    /**
     * @Description: 喜欢
     * @Param:[userId, publishId]
     * @return:boolean
     * @Author:JinboYang
     * @Date:2021/1/7
     */
    @Override
    public boolean saveLoveComment(Long userId, String publishId) {
        Query query = Query.query(Criteria.where("userId").is(userId)
                .and("publishId").is(new ObjectId(publishId))
                .and("commentType").is(3));
        long count = this.mongoTemplate.count(query, Comment.class);
        if (count > 0) {
            return false;
        }
        return this.saveComment(userId, publishId, 3, null);
    }

    /**
     * @Description: 保存评论
     * @Param:[userId, publishId, type, content]
     * @return:boolean
     * @Author:JinboYang
     * @Date:2021/1/7
     */
    @Override
    public boolean saveComment(Long userId, String publishId, Integer type, String content) {
        try {
            Comment comment = new Comment();
            comment.setId(ObjectId.get());
            comment.setPublishId(new ObjectId(publishId));
            comment.setContent(content);
            comment.setUserId(userId);
            comment.setCommentType(type);
            comment.setIsParent(true);
            comment.setCreated(System.currentTimeMillis());

            //设置发布人的id
            Publish publish = this.mongoTemplate.findById(comment.getPublishId(), Publish.class);
            if (publish != null) {
                comment.setPublishUserId(publish.getUserId());
            } else {
                Video video = this.mongoTemplate.findById(comment.getPublishId(), Video.class);
                if (video != null) {
                    comment.setPublishUserId(video.getUserId());
                }
            }

            //进行保存
            this.mongoTemplate.save(comment);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    @Override
    public Long queryCommentCount(String publishId, Integer type) {
        Query query = Query.query(Criteria.where("publishId").is(new ObjectId(publishId)).and("commentType").is(type));
        return this.mongoTemplate.count(query, Comment.class);
    }

    /**
     * @Description: 根据id查询
     * @Param:[id]
     * @return:com.tanhua.dubbo.server.pojo.Publish
     * @Author:JinboYang
     * @Date:2021/1/7
     */
    @Override
    public Publish queryPublishById(String id) {
        Query query = Query.query(Criteria.where("id").is(id));
        return this.mongoTemplate.findOne(query, Publish.class);
    }

    @Override
    public PageInfo<Comment> queryCommentList(String publishId, Integer page, Integer pageSize) {

        PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.desc("created")));
        Query query = Query.query(Criteria.where("publishId").is(new ObjectId(publishId)).and("commentType").is(2)).with(pageRequest);
        List<Comment> comments = this.mongoTemplate.find(query, Comment.class);
        return new PageInfo<>(0, page, pageSize, comments);
    }

    /**
     * @Description: 根据用户查询评论列表
     * @Param:[userId, type, page, pageSize]
     * @return:com.tanhua.dubbo.server.vo.PageInfo<com.tanhua.dubbo.server.pojo.Comment>
     * @Author:JinboYang
     * @Date:2021/1/11
     */
    @Override
    public PageInfo<Comment> queryCommentListByUser(Long userId, Integer type, Integer page, Integer pageSize) {
        PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.desc("created")));
        Query query = Query.query(Criteria.where("publishUserId").is(userId).and("commentType").is(type)).with(pageRequest);
        List<Comment> commentList = this.mongoTemplate.find(query, Comment.class);

        PageInfo<Comment> pageInfo = new PageInfo<>();
        pageInfo.setTotal(0);
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        pageInfo.setRecords(commentList);
        return pageInfo;

    }

    @Override
    public List<Publish> queryPublishByPids(List<Long> pids) {
        Query query = Query.query(Criteria.where("pid").in(pids));
        return this.mongoTemplate.find(query, Publish.class);
    }

    /**
     * @Description: 查询相册表
     * @Param:[userId, page, pageSize]
     * @return:com.tanhua.dubbo.server.vo.PageInfo<com.tanhua.dubbo.server.pojo.Publish>
     * @Author:JinboYang
     * @Date:2021/1/13
     */
    @Override
    public PageInfo<Publish> queryAlbumList(Long userId, Integer page, Integer pageSize) {
        PageInfo<Publish> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        pageInfo.setTotal(0);

        Query query = new Query().with(Sort.by(Sort.Order.desc("created")));
        List<Album> albumList = this.mongoTemplate.find(query, Album.class, "quanzi_album_" + userId);

        if(CollectionUtils.isEmpty(albumList)){
            return pageInfo;
        }

        List<ObjectId> publishIds = new ArrayList<>();
        for (Album album : albumList) {
            publishIds.add(album.getPublishId());
        }

        //查询发布信息
        Query queryPublish = Query.query(Criteria.where("id").in(publishIds)).with(Sort.by(Sort.Order.desc("created")));
        List<Publish> publishList = this.mongoTemplate.find(queryPublish, Publish.class);

        pageInfo.setRecords(publishList);
        return pageInfo;
    }

    /**
     * @Description: 活跃数
     * @Param:[thisYearTimeList, lastYearTimeList]
     * @return:java.util.List<java.lang.Integer>
     * @Author:JinboYang
     * @Date:2021/1/17
     */
    @Override
    public List<Integer> queryCommentCounts(List<Long> thisYearTimeList, List<Long> lastYearTimeList) {
        List<Integer> userIdList=new ArrayList<>();
        for (int i = 0; i < thisYearTimeList.size()-1; i++) {
            Set<Long> thisYearByTime = getActiveByTime(thisYearTimeList.get(i), thisYearTimeList.get(i + 1));
            Set<Long> lastYearByTime = getActiveByTime(lastYearTimeList.get(i), lastYearTimeList.get(i + 1));
            userIdList.add(thisYearByTime.size());
            userIdList.add(lastYearByTime.size());
        }
        return userIdList;
    }

    /**
     * @Description: 获取活跃数
     * @Param:[startDate, endDate]
     * @return:java.util.Set<java.lang.Long>
     * @Author:JinboYang
     * @Date:2021/1/17
     */
    public Set<Long> getActiveByTime(Long startDate, Long endDate){
        Criteria startCriteria = Criteria.where("created").gte(startDate);
        Criteria endCriteria = Criteria.where("created").lt(endDate);
        Criteria criteria = new Criteria().andOperator(startCriteria, endCriteria);

        Query query = Query.query(criteria);
        List<Log> logList = this.mongoTemplate.find(query, Log.class);
        Set<Long> userIds = new HashSet<>();
        for (Log log1 : logList) {
            userIds.add(log1.getUserId());
        }
        return userIds;
    }


    /**
     * @Description: 查询次日留存率
     * @Param:[nextList, thisYearTimeList, lastYearTimeList]
     * @return:java.util.List<java.lang.Integer>
     * @Author:JinboYang
     * @Date:2021/1/17
     */
    @Override
    public List<Integer> queryNextDay(List<List<Long>> nextList, List<Long> thisYearTimeList, List<Long> lastYearTimeList) {

        List<Integer> loginCounts = new ArrayList<>();
        // createdIdList里 是对应时间段的前一天新建用户的id
        int i = 0;
        for (int j = 0; j < (thisYearTimeList.size() - 1) << 1; j += 2) {
            // 在此时间段登录的 并且是对应时间段id里的 是算作次日留存的用户
            Criteria thisStartCriteria = Criteria.where("loginDate").gte(thisYearTimeList.get(i));
            Criteria thisEndCriteria = Criteria.where("loginDate").lt(thisYearTimeList.get(i + 1));
            Criteria thisCriteria =  Criteria.where("userId").in(nextList.get(j)).andOperator(thisStartCriteria, thisEndCriteria);

            Criteria lastStartCriteria = Criteria.where("loginDate").gte(thisYearTimeList.get(i));
            Criteria lastEndCriteria = Criteria.where("loginDate").lt(thisYearTimeList.get(i++ + 1));
            Criteria lastCriteria = Criteria.where("userId").in(nextList.get(j + 1)).andOperator(lastStartCriteria, lastEndCriteria);

            Query thisYearQuery = Query.query(thisCriteria);
            Query lastYearQuery = Query.query(lastCriteria);

            long thisYearCount = this.mongoTemplate.count(thisYearQuery, UserLogin.class);
            long lastYearCount = this.mongoTemplate.count(lastYearQuery, UserLogin.class);
            // 先存今年 后存去年(索引偶数为今年, 奇数为去年)
            loginCounts.add((int) thisYearCount);
            loginCounts.add((int) lastYearCount);
        }
        return loginCounts;
    }

    /**
     * @Description: 过去30天活跃用户
     * @Param:[oldDate, nowTime]
     * @return:java.lang.Integer
     * @Author:JinboYang
     * @Date:2021/1/18
     */
    public Integer queryActivePassMonth(DateTime oldDate, DateTime nowTime) {
        return this.getActiveByTime(DateUtil.offsetDay(oldDate, -30).getTime(), nowTime.getTime()).size();
    }

    /**
       * @Description: 七天活跃
       * @Param:[sevenDate, zeroTime]
       * @return:java.lang.Integer
       * @Author:JinboYang
       * @Date:2021/1/19
       */
    @Override
    public Integer queryActiveSevenDays(DateTime sevenDate, DateTime zeroTime) {
        return this.getActiveByTime(DateUtil.offsetDay(zeroTime, -7).getTime(), zeroTime.getTime()).size();
    }

    /**
     * @Description: 根据时间查询登录人数
     * @Param:[zeroTime, nowTime]
     * @return:java.lang.Integer
     * @Author:JinboYang
     * @Date:2021/1/18
     */
    @Override
    public Integer queryLoginCountByTime(DateTime zeroTime, DateTime nowTime) {
        Criteria startCriteria = Criteria.where("loginDate").gte(zeroTime.getTime());
        Criteria endCriteria = Criteria.where("loginDate").lt(nowTime.getTime());
        Criteria criteria = new Criteria().andOperator(startCriteria, endCriteria);

        Query query = Query.query(criteria);
        List<UserLogin> userLogins = this.mongoTemplate.find(query, UserLogin.class);
        Set<Long> userIds = new HashSet<>();
        for (UserLogin userLogin : userLogins) {
            userIds.add(userLogin.getUserId());
        }
        return userIds.size();
    }

    @Override
    public List<Integer> queryLoginCount(List<List<Long>> createdIdList, List<Long> thisYearTimeList, List<Long> lastYearTimeList) {
        List<Integer> loginCounts = new ArrayList<>();
        // createdIdList里 是对应时间段的前一天新建用户的id
        for (int i = 0; i < thisYearTimeList.size() - 1; i += 2) {
            // 在此时间段登录的 并且是对应时间段id里的 是算作次日留存的用户
            Criteria thisStartCriteria = Criteria.where("created").gte(thisYearTimeList.get(i));
            Criteria thisEndCriteria = Criteria.where("created").lt(thisYearTimeList.get(i + 1));
            Criteria thisCriteria = Criteria.where("userId").in(createdIdList.get(i)).andOperator(thisStartCriteria, thisEndCriteria);

            Criteria lastStartCriteria = Criteria.where("created").gte(thisYearTimeList.get(i));
            Criteria lastEndCriteria = Criteria.where("created").lt(thisYearTimeList.get(i + 1));
            Criteria lastCriteria = Criteria.where("userId").in(createdIdList.get(i + 1)).andOperator(lastStartCriteria, lastEndCriteria);

            Query thisYearQuery = Query.query(thisCriteria);
            Query lastYearQuery = Query.query(lastCriteria);

            long thisYearCount = this.mongoTemplate.count(thisYearQuery, UserLogin.class);
            long lastYearCount = this.mongoTemplate.count(lastYearQuery, UserLogin.class);
            // 先存今年 后存去年(索引偶数为今年, 奇数为去年)
            loginCounts.add((int) thisYearCount);
            loginCounts.add((int) lastYearCount);
        }
        return loginCounts;
    }

    /**
     * @Description: 查询活跃人数
     * @Param:[zeroTime, nowTime]
     * @return:java.lang.Integer
     * @Author:JinboYang
     * @Date:2021/1/18
     */
    @Override
    public Integer queryActiveUserByTime(DateTime zeroTime, DateTime nowTime) {
        return this.getActiveByTime(DateUtil.beginOfDay(nowTime).getTime(), nowTime.getTime()).size();
    }

}
